﻿using System;
using System.Collections;
using System.Collections.Generic;
using Pfz.Collections;

namespace Pfz.RemoteGaming
{
	/// <summary>
	/// Dictionary of property changes.
	/// </summary>
	public sealed class RemoteGamePropertyChanges:
		IReadOnlyDictionary<RemoteGameProperty, RemoteGamePropertyChange>
	{
		private Dictionary<RemoteGameProperty, RemoteGamePropertyChange> _dictionary = new Dictionary<RemoteGameProperty,RemoteGamePropertyChange>();
		internal RemoteGamePropertyChanges()
		{
		}
		
		#region Public Methods
			/// <summary>
			/// Gets the Properties that changed.
			/// </summary>
			public ICollection<RemoteGameProperty> Keys
			{
				get
				{
					return _dictionary.Keys;
				}
			}

			/// <summary>
			/// Gets the value changes.
			/// </summary>
			public ICollection<RemoteGamePropertyChange> Values
			{
				get
				{
					return _dictionary.Values;
				}
			}

			/// <summary>
			/// Gets the value change for a given property;
			/// </summary>
			public RemoteGamePropertyChange this[RemoteGameProperty key]
			{
				get
				{
					return _dictionary[key];
				}
			}

			/// <summary>
			/// Checks if a given property is in the dictionary.
			/// </summary>
			public bool ContainsKey(RemoteGameProperty key)
			{
				return _dictionary.ContainsKey(key);
			}

			/// <summary>
			/// Checks if a given change is in the dictionary.
			/// </summary>
			public bool ContainsValue(RemoteGamePropertyChange value)
			{
				return _dictionary.ContainsValue(value);
			}

			/// <summary>
			/// Tries to get the change for a given property.
			/// </summary>
			public bool TryGetValue(RemoteGameProperty key, out RemoteGamePropertyChange value)
			{
				return _dictionary.TryGetValue(key, out value);
			}

			/// <summary>
			/// Gets the number of elements in this dictionary.
			/// </summary>
			public int Count
			{
				get
				{
					return _dictionary.Count;
				}
			}

			/// <summary>
			/// Enumerates all the changes in this dictionary.
			/// </summary>
			public IEnumerator<KeyValuePair<RemoteGameProperty, RemoteGamePropertyChange>> GetEnumerator()
			{
				return _dictionary.GetEnumerator();
			}
		#endregion

		#region _Set
			internal void _Set(RemoteGameProperty property, RemoteGamePropertyChange change)
			{
				RemoteGamePropertyChange oldChange;
				if (!_dictionary.TryGetValue(property, out oldChange))
				{
					if (object.Equals(change.OldValue, change.NewValue))
						return;

					_dictionary.Add(property, change);
					return;
				}

				if (object.Equals(change.OldValue, change.NewValue))
				{
					_dictionary.Remove(property);
					return;
				}

				change = new RemoteGamePropertyChange(oldChange.OldValue, change.NewValue);
				_dictionary[property] = change;
			}
		#endregion

		#region IReadOnlyDictionary
			object IReadOnlyDictionary.this[object key]
			{
				get
				{
					return _dictionary[(RemoteGameProperty)key];
				}
			}

			bool IReadOnlyDictionary.ContainsKey(object key)
			{
				if (key == null)
					throw new ArgumentNullException("key");

				var property = key as RemoteGameProperty;
				if (property == null)
					return false;

				return _dictionary.ContainsKey(property);
			}

			bool IReadOnlyDictionary.ContainsValue(object value)
			{
				return _dictionary.ContainsValue((RemoteGamePropertyChange)value);
			}

			bool IReadOnlyDictionary.TryGetValue(object key, out object value)
			{
				RemoteGamePropertyChange change;
				if (_dictionary.TryGetValue((RemoteGameProperty)key, out change))
				{
					value = change;
					return true;
				}

				value = null;
				return false;
			}

			IEnumerator IEnumerable.GetEnumerator()
			{
				return _dictionary.GetEnumerator();
			}


			ICollection IReadOnlyDictionary.Keys
			{
				get
				{
					return _dictionary.Keys;
				}
			}

			ICollection IReadOnlyDictionary.Values
			{
				get
				{
					return _dictionary.Values;
				}
			}
		#endregion
	}
}
